package pro.chenggang.project.reactive.mybatis.support.generator.support;

import org.apache.commons.lang3.StringUtils;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.JavaVisibility;
import org.mybatis.generator.api.dom.java.TopLevelClass;
import org.mybatis.generator.config.Context;
import pro.chenggang.project.reactive.mybatis.support.generator.option.LombokConfig;
import pro.chenggang.project.reactive.mybatis.support.generator.properties.GeneratorProperties;
import pro.chenggang.project.reactive.mybatis.support.generator.properties.GeneratorPropertiesHolder;

import java.util.Objects;
import java.util.Set;

/**
 * Generated model customizer
 *
 * @author Gang Cheng
 * @version 1.0.0
 * @since 1.0.0
 */
public class GeneratedModelCustomizer {

    /**
     * customize lombok
     *
     * @param topLevelClass     the TopLevelClass
     * @param introspectedTable the IntrospectedTable
     */
    public void customizeLombok(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        String tableRemarks = StringUtils.defaultIfBlank(introspectedTable.getRemarks(), "auto generated");
        topLevelClass.addJavaDocLine("/**");
        topLevelClass.addJavaDocLine(" * " + tableRemarks);
        topLevelClass.addJavaDocLine(" * ");
        topLevelClass.addJavaDocLine(" * @author AutoGenerated");
        topLevelClass.addJavaDocLine(" */");
        topLevelClass.getFields().forEach(field -> field.setVisibility(JavaVisibility.PROTECTED));
        GeneratorProperties generatorProperties = GeneratorPropertiesHolder.getInstance().getGeneratorProperties();
        Set<LombokConfig> lombokConfigs = generatorProperties.getLombokConfigs();
        if (Objects.isNull(lombokConfigs) || lombokConfigs.isEmpty()) {
            return;
        }
        lombokConfigs.forEach(lombok -> {
            switch (lombok) {
                case Getter:
                    topLevelClass.addImportedType("lombok.Getter");
                    topLevelClass.addAnnotation("@Getter");
                    break;
                case Setter:
                    topLevelClass.addImportedType("lombok.Setter");
                    topLevelClass.addAnnotation("@Setter");
                    break;
                case ToString:
                    topLevelClass.addImportedType("lombok.ToString");
                    topLevelClass.addAnnotation("@ToString");
                    break;
                case Data:
                    topLevelClass.addImportedType("lombok.Data");
                    topLevelClass.addAnnotation("@Data");
                    break;
                case Builder:
                    topLevelClass.addImportedType("lombok.Builder");
                    topLevelClass.addAnnotation("@Builder");
                    break;
                case NoArgsConstructor:
                    topLevelClass.addImportedType("lombok.NoArgsConstructor");
                    topLevelClass.addAnnotation("@NoArgsConstructor");
                    break;
                case AllArgsConstructor:
                    topLevelClass.addImportedType("lombok.AllArgsConstructor");
                    topLevelClass.addAnnotation("@AllArgsConstructor");
                    break;
                case EqualsAndHashCode:
                    topLevelClass.addImportedType("lombok.EqualsAndHashCode");
                    topLevelClass.addAnnotation("@EqualsAndHashCode");
                    break;
                case AccessorsChain:
                    topLevelClass.addImportedType("lombok.experimental.Accessors");
                    topLevelClass.addAnnotation("@Accessors(chain = true)");
                    break;
                case AccessorsFluent:
                    topLevelClass.addImportedType("lombok.experimental.Accessors");
                    topLevelClass.addAnnotation("@Accessors(fluent = true)");
                    break;
                default:
            }
        });
    }

    /**
     * customize model constant
     *
     * @param topLevelClass     the TopLevelClass
     * @param introspectedTable the IntrospectedTable
     */
    public void customizeModelConstant(Context context, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        for (IntrospectedColumn introspectedColumn : introspectedTable.getAllColumns()) {
            Field field = new Field(introspectedColumn.getActualColumnName().toUpperCase(), new FullyQualifiedJavaType(String.class.getName()));
            field.setVisibility(JavaVisibility.PUBLIC);
            field.setStatic(true);
            field.setFinal(true);
            field.setInitializationString("\"" + introspectedColumn.getJavaProperty() + "\"");
            context.getCommentGenerator().addClassComment(topLevelClass, introspectedTable);
            topLevelClass.addField(field);
            Field columnField = new Field("DB_" + introspectedColumn.getActualColumnName().toUpperCase(), new FullyQualifiedJavaType(String.class.getName()));
            columnField.setVisibility(JavaVisibility.PUBLIC);
            columnField.setStatic(true);
            columnField.setFinal(true);
            columnField.setInitializationString("\"" + introspectedColumn.getActualColumnName() + "\"");
            topLevelClass.addField(columnField);
        }
    }
}
